import time

import pandas as pd
import os,random,sys,codecs,datetime
from datetime import date
import random
import configparser
import logging,easyquotation

DMAErrorPass="证券代码无效&该柜台暂不支持北交所或股转交易&custBatchNo已经存在"
#记录日志到本地
def logfun(isfile):

    logger = logging.getLogger()
    # 输出到console
    # logger.setLevel(level=logging.DEBUG)
    logger.setLevel(level=logging.INFO) # 某些python库文件中有一些DEBUG级的输出信息，如果这里设置为DEBUG，会导致console和log文件中写入海量信息
    # console_formatter = colorlog.ColoredFormatter(
    #     # fmt='%(log_color)s[%(asctime)s.%(msecs)03d] %(filename)s -> %(funcName)s line:%(lineno)d [%(levelname)s] : %(message)s',
    #     fmt=' %(levelname)s: %(message)s'
    #     # datefmt='%Y-%m-%d  %H:%M:%S'
    # )
    console = logging.StreamHandler()  # 输出到console的handler
    console.setLevel(logging.INFO)
    # console.setFormatter(console_formatter)
    logger.addHandler(console)
    # 输出到文件
    if isfile:
        # 设置文件名
        now = datetime.datetime.now()
        filename = f"log_{now.strftime('%Y-%m-%d_%H-%M-%S')}.txt"
        log_path=os.path.join(os.getcwd(),'log')
        if not os.path.exists(log_path):
            os.mkdir(log_path)
        logfile = log_path + '/'+filename
        # 设置文件日志格式
        filer = logging.FileHandler(logfile,mode='w') # 输出到log文件的handler
        # filer.setLevel(level=logging.DEBUG)
        file_formatter = logging.Formatter(
            fmt='%(asctime)s - %(levelname)s: %(message)s'
        )
        # formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
        filer.setFormatter(file_formatter)
        logger.addHandler(filer)

    return logger

#获取本地路径下的基础数据
def joinPath(fileName,subCatalog):
    pyPath=os.path.dirname(os.path.realpath(sys.argv[0]))
    if subCatalog=="":
        filePath=os.path.join(pyPath,fileName)
    else:
        pyPath=os.path.join(pyPath,subCatalog)
        if os.path.exists(pyPath):
            pass
        else:
            os.mkdir(pyPath)
        filePath=os.path.join(pyPath,fileName)
    return filePath

def CSV_2_UTF8(src, dst):
    content = ReadFile(src)
    WriteFile(dst, content, encoding="utf-8")
def ReadFile(filePath):
    with codecs.open(filePath, "r") as f:
        return f.read()
def WriteFile(filePath, u, encoding="utf-8"):
    # with codecs.open(filePath,"w",encoding) as f:
    with codecs.open(filePath, "wb") as f:
        f.write(u.encode(encoding, errors="ignore"))
def check_string_contains_element(string, elements):
    return any(element in string for element in elements)

#  指定目录下,将数据带时间后缀保存为csv格式
def saveCsvByTime(fileNanme,saveData,TimeFlag,encondingType,subCatalog):
    # OQPath:导出目录,fileNanme：文件名前缀,saveData：保存的数据，subCatalog是否需要子目录
    now = datetime.datetime.now()
    if TimeFlag==True:
        filename = f"{fileNanme}_{now.strftime('%Y-%m-%d_%H-%M-%S')}.csv"
    else:
        filename = f"{fileNanme}.csv"
    if subCatalog=="":
        full_path = joinPath(filename,"")
    else:
        full_path = joinPath(filename,subCatalog)
    if  encondingType=="ANSI":
        saveData.to_csv(full_path,index=False,encoding="ANSI")
    else:
        saveData.to_csv(full_path,index=False)

def 判断DMA时序是否一致():
    自然日=datetime.datetime.now().strftime("%Y%m%d")

    CSV_2_UTF8(os.path.join(DMADir,"algoOrder_"+自然日+".csv"), os.path.join(DMADir,"algoOrder_"+自然日+"_utf.csv"))
    CSV_2_UTF8(os.path.join(DMADir,"execResult_"+自然日+".csv"), os.path.join(DMADir,"execResult_"+自然日+"_utf.csv"))
    algoOrder =pd.read_csv(os.path.join(DMADir, 'algoOrder_' + 自然日 + '_utf.csv'))
    execResult=pd.read_csv(os.path.join(DMADir, 'execResult_' + 自然日 + '_utf.csv'))
    代码列表=list(set(algoOrder["symbol"].tolist()))
    for 代码 in 代码列表:
        代码匹配记录=algoOrder[algoOrder["symbol"]==代码]
        list_range=list(set(代码匹配记录["custBatchNo"].tolist()))
        filtered = execResult[execResult['custBatchNo'].isin(list_range) &(execResult['status']==2)]
        is_ascending = filtered['custBatchNo'].is_monotonic_increasing
        if is_ascending==False:
            log.info(f"★★★★★★代码：{代码}，algoOrder跟execResult时序存在不一致:")
            non_ascending_rows = filtered[~filtered['custBatchNo'].diff().ge(0)]
            log.info(non_ascending_rows)
    客户批号=list(set(algoOrder["custBatchNo"].tolist()))
    execResult未找到记录=0
    execResult未找到记录已发送的记录=0
    execResult未找到记录已发送成功或失败的记录=0
    execResult找到记录发送未知=0
    execResult不在白名单发送失败=0
    for 批号 in 客户批号:
        批号匹配记录=execResult[execResult["custBatchNo"]==批号]
        if len(批号匹配记录)==0:
            log.info(f"该客户批号{批号}在execResult未找到记录")
            execResult未找到记录=execResult未找到记录+1
        else:
            已发送批号匹配记录=execResult[(execResult["custBatchNo"]==批号)&(execResult["status"]==0)]
            if len(已发送批号匹配记录)==0:
                log.info(f"该客户批号{批号}在execResult未找到记录已发送的记录")
                execResult未找到记录已发送的记录=execResult未找到记录已发送的记录+1
            成功批号匹配记录=execResult[(execResult["custBatchNo"]==批号)&(execResult["status"]==2)]
            if len(成功批号匹配记录)==0:
                未找到成功但是失败=execResult[execResult["status"]==1]
                if len(未找到成功但是失败)==0:
                    log.info(f"该客户批号{批号}在execResult未找到记录已发送成功或失败的记录")
                    execResult未找到记录已发送成功或失败的记录=execResult未找到记录已发送成功或失败的记录+1
            失败批号匹配记录=execResult[(execResult["custBatchNo"]==批号)&(execResult["status"]==1)]
            if len(失败批号匹配记录)>0:
                错误原因=失败批号匹配记录['errorMsg'].iloc[-1]
                if check_string_contains_element(错误原因, DMAErrorPass)==False:
                    log.info(f"该客户批号{批号}在execResult找到记录已发送失败的记录：{错误原因}")
                    execResult不在白名单发送失败=execResult不在白名单发送失败+1
            未知批号匹配记录=execResult[(execResult["custBatchNo"]==批号)&(execResult["status"]==3)]
            if len(未知批号匹配记录)>0:
                log.info(f"该客户批号{批号}在execResult找到记录发送未知的记录")
                execResult找到记录发送未知=execResult找到记录发送未知+1
    log.info(f"algoOrder跟execResult的custBatchNo，存在{execResult未找到记录}笔记录execResult未找到custBatchNo记录，"
             f"存在{execResult未找到记录已发送的记录}笔记录execResult未找到已发送的记录，"
             f"存在{execResult未找到记录已发送成功或失败的记录}笔记录execResult未找到已发送成功或失败的记录，"
             f"存在{execResult找到记录发送未知}笔记录execResult找到记录发送未知，"
             f"存在{execResult不在白名单发送失败}笔记录execResult不在白名单发送失败，")


def 判断algo时序是否一致():
    自然日=datetime.datetime.now().strftime("%Y%m%d")

    CSV_2_UTF8(os.path.join(AlgoDir,"algoStart_"+自然日+".csv"), os.path.join(AlgoDir,"algoStart_"+自然日+"_utf.csv"))
    CSV_2_UTF8(os.path.join(AlgoDir,"algoExecStatic_"+自然日+".csv"), os.path.join(AlgoDir,"algoExecStatic_"+自然日+"_utf.csv"))
    algoOrder =pd.read_csv(os.path.join(AlgoDir, 'algoStart_' + 自然日 + '_utf.csv'))
    execResult=pd.read_csv(os.path.join(AlgoDir, 'algoExecStatic_' + 自然日 + '_utf.csv'))
    客户批号=list(set(algoOrder["custAlgoNo"].tolist()))
    execResult未找到记录=0
    execResult仅有待启动记录=0
    execResult找到已完成记录=0
    execResult找到已过期记录=0
    execResult找到错误记录=0
    for 批号 in 客户批号:
        批号匹配记录=execResult[execResult["custAlgoNo"]==批号]
        if len(批号匹配记录)==0:
            log.info(f"该客户批号{批号}在algoExecStatic未找到记录")
            execResult未找到记录=execResult未找到记录+1
        else:
            待启动批号匹配记录=execResult[(execResult["custAlgoNo"]==批号)&(execResult["status"]==1)]
            if len(待启动批号匹配记录)>0:
                仅找到待启动匹配记录=execResult[(execResult["custAlgoNo"]==批号) & ((execResult["status"]==1) | (execResult["status"]==2) | (execResult["status"]==3) | (execResult["status"]==5) | (execResult["status"]==6) | (execResult["status"]==7) | (execResult["status"]==8))]
                if len(仅找到待启动匹配记录)==0:
                    log.info(f"该客户批号{批号}在algoExecStatic仅找到待启动的记录")
                    execResult仅有待启动记录=execResult仅有待启动记录+1
            已完成匹配记录=execResult[(execResult["custAlgoNo"]==批号)&(execResult["status"]==6)]
            if len(已完成匹配记录)>0:
                execResult找到已完成记录=execResult找到已完成记录+1
            已过期匹配记录=execResult[(execResult["custAlgoNo"]==批号)&(execResult["status"]==7)]
            if len(已过期匹配记录)>0:
                execResult找到已过期记录=execResult找到已过期记录+1
            错误匹配记录=execResult[(execResult["custAlgoNo"]==批号)&(execResult["status"]==8)]
            if len(错误匹配记录)>0:
                execResult找到错误记录=execResult找到错误记录+1
    log.info(f"algoStart跟algoExecStatic的custAlgoNo，存在{execResult未找到记录}笔记录algoExecStatic未找到custAlgoNo记录，"
             f"存在{execResult仅有待启动记录}笔记录algoExecStatic仅有待启动的记录，"
             f"存在{execResult找到已完成记录}笔记录algoExecStatic算法已完成，"
             f"存在{execResult找到已过期记录}笔记录algoExecStatic算法母单已过期，"
             f"存在{execResult找到错误记录}笔记录algoExecStatic算法母单失败，")



def 统计交易下单联通性():
    自然日=datetime.datetime.now().strftime("%Y%m%d")
    CSV_2_UTF8(os.path.join(DMADir,"orderUpdate_"+自然日+".csv"), os.path.join(DMADir,"orderUpdate_"+自然日+"_utf.csv"))
    CSV_2_UTF8(os.path.join(DMADir,"tradeUpdate_"+自然日+".csv"), os.path.join(DMADir,"tradeUpdate_"+自然日+"_utf.csv"))
    orderUpdate =pd.read_csv(os.path.join(DMADir, 'orderUpdate_' + 自然日 + '_utf.csv'))
    tradeUpdate=pd.read_csv(os.path.join(DMADir, 'tradeUpdate_' + 自然日 + '_utf.csv'))

    orderUpdate["证券分类"]=orderUpdate["symbol"].str[:2].apply(lambda x:"深市主板" if x=="00"
                                        else "深市可转债" if x=="11"
                                      else "深市创业板" if x=="30"
                                        else "深市ETF基金" if x=="15"
                                      else "沪市主板" if x=="60"
                                        else "沪市可转债" if x=="12"
                                      else "沪市ETF基金" if x=="51" else "沪市ETF基金" if x=="56"  else "沪市ETF基金" if x=="58"
                                        else "沪市科创板" if x=="68"
                                        else "北交所股票" if x=="43"
                                        else "北交所股票" if x=="83"
                                        else "北交所股票" if x=="87"
                                        else "北交所股票" if x=="92"
                                       else '--')
    tradeUpdate["证券分类"]=tradeUpdate["symbol"].str[:2].apply(lambda x:"深市主板" if x=="00"
                                        else "深市可转债" if x=="11"
                                      else "深市创业板" if x=="30"
                                        else "深市ETF基金" if x=="15"
                                      else "沪市主板" if x=="60"
                                        else "沪市可转债" if x=="12"
                                      else "沪市ETF基金" if x=="51" else "沪市ETF基金" if x=="56"  else "沪市ETF基金" if x=="58"
                                        else "沪市科创板" if x=="68"
                                        else "北交所股票" if x=="43"
                                        else "北交所股票" if x=="83"
                                        else "北交所股票" if x=="87"
                                        else "北交所股票" if x=="92"
                                       else '--')

    交易下单连通性=pd.DataFrame(columns=["委托状态","账户类型","证券类型","普通买入","普通卖出","融资买入","融券卖出","卖券还款","买券还券"])
    for 委托状态 in [0,1,2,3,4,5,7,8]:
        for 账户类型 in ["UM0","UF0","AT0","UMC","ATC"]:
            for 证券分类 in ["深市主板","深市可转债","深市创业板","深市ETF基金","沪市主板","沪市可转债","沪市ETF基金","沪市科创板","北交所股票"]:
                new_data=[委托状态,账户类型,证券分类,0,0,0,0,0,0]
                for 交易方向 in["1","2","A","B","C","D"]:
                    匹配委托=orderUpdate[(orderUpdate["acctType"]==账户类型) &(orderUpdate["证券分类"]==证券分类) &(orderUpdate["tradeSide"]==交易方向)&(orderUpdate["status"]==委托状态)]
                    记录数=len(匹配委托)
                    new_data[["1","2","A","B","C","D"].index(交易方向)+3]=记录数
                if 账户类型 not in ["UMC","ATC"]:
                    new_data[5],new_data[6],new_data[7],new_data[8]="NUll","NUll","NUll","NUll"
                添加记录=pd.DataFrame([new_data])
                添加记录.columns=["委托状态","账户类型","证券类型","普通买入","普通卖出","融资买入","融券卖出","卖券还款","买券还券"]
                交易下单连通性=pd.concat([交易下单连通性,添加记录])
    交易下单连通性["委托状态"]=交易下单连通性["委托状态"].apply(lambda x:"已报" if x==0
                                        else "部分成交" if x==1
                                      else "完全成交" if x==2
                                        else "部分撤单" if x==3
                                      else "全部撤单" if x==4
                                        else "订单拒绝" if x==5
                                      else "正报" if x==7
                                        else "撤销中" if x==8
                                                  else '--')
    saveCsvByTime("委托明细执行统计",交易下单连通性,False,"","outPut")
    log.info("已生成委托明细执行统计")
    交易成交连通性=pd.DataFrame(columns=["账户类型","证券类型","普通买入","普通卖出","融资买入","融券卖出","卖券还款","买券还券"])
    for 账户类型 in ["UM0","UF0","AT0","UMC","ATC"]:
         for 证券分类 in ["深市主板","深市可转债","深市创业板","深市ETF基金","沪市主板","沪市可转债","沪市ETF基金","沪市科创板","北交所股票"]:
            new_data=[账户类型,证券分类,0,0,0,0,0,0]
            for 交易方向 in["1","2","A","B","C","D"]:
                匹配委托=tradeUpdate[(tradeUpdate["acctType"]==账户类型) &(tradeUpdate["证券分类"]==证券分类) &(tradeUpdate["tradeSide"]==交易方向)&(tradeUpdate["tradeType"]=="F")]
                记录数=len(匹配委托)
                new_data[["1","2","A","B","C","D"].index(交易方向)+2]=记录数
            if 账户类型 not in ["UMC","ATC"]:
                new_data[4],new_data[5],new_data[6],new_data[7]="NUll","NUll","NUll","NUll"
            添加记录=pd.DataFrame([new_data])
            添加记录.columns=["账户类型","证券类型","普通买入","普通卖出","融资买入","融券卖出","卖券还款","买券还券"]
            交易成交连通性=pd.concat([交易成交连通性,添加记录])
    saveCsvByTime("成交明细执行统计",交易成交连通性,False,"","outPut")
    log.info("已生成成交明细执行统计")
log=logfun(isfile=True)
DMADir="./DMA算法"
AlgoDir="./算法单导入"
print("开始判断DMA算法：algoOrder跟execResult时序")
判断DMA时序是否一致()
print("开始判断算法单导入：algoStart跟algoExecStatic时序")
判断algo时序是否一致()
print("开始判断委托明细和成交明细执行情况")
统计交易下单联通性()


input("Press Enter to exit…")
